package com.weyoung.app.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weyoung.app.controller.FileController;
import com.weyoung.app.dto.resp.UserLoginRespDTO;
import com.weyoung.app.mapper.UserDetailMapper;
import com.weyoung.app.mapper.UserMapper;
import com.weyoung.app.service.UserService;
import com.weyoung.common.consatant.exception.ClientException;
import com.weyoung.common.consatant.result.Result;
import com.weyoung.common.enums.UserErrorCodeEnum;
import com.weyoung.app.dto.req.UserLoginReqDTO;
import com.weyoung.app.dto.req.UserRegisterReqDTO;
import com.weyoung.common.model.entity.UserDO;
import com.weyoung.common.model.entity.UserDetailDO;
import com.weyoung.common.utils.AES;
import com.weyoung.common.utils.ShareCodeUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements UserService {

    private final StringRedisTemplate stringRedisTemplate;
    private final UserMapper userMapper;
    private final FileController fileController;
    private final UserDetailMapper userDetailMapper;

    @Override
    public UserLoginRespDTO login(UserLoginReqDTO requestParam) {
        LambdaQueryWrapper<UserDO> queryWrapper = Wrappers.lambdaQuery(UserDO.class)
                .eq(UserDO::getUsername, requestParam.getUsername());
        UserDO userDO = baseMapper.selectOne(queryWrapper);
        if (userDO == null) {
            throw new ClientException(UserErrorCodeEnum.USER_NULL);
        }
        if (!userDO.getPassword().equals(AES.encrypt(requestParam.getPassword()))) {
            throw new ClientException(UserErrorCodeEnum.USER_PASSWORD_ERROR);
        }
        StpUtil.login(userDO.getUserId());

        // 将 user_id 和 family_id 存入 Redis
        if (userDO.getFamilyId() != null){
            String userIdKey = String.valueOf(userDO.getUserId());
            stringRedisTemplate.opsForValue().set(userIdKey, String.valueOf(userDO.getFamilyId()));
         }

        return UserLoginRespDTO.builder()
                .userId(userDO.getUserId())
                .username(userDO.getUsername())
                .role(userDO.getRole())
                .token(StpUtil.getTokenValue())
                .userPic(userDO.getUserPic())
                .build();
    }

    @Override
    public Void register(UserRegisterReqDTO requestParam) {
        UserDO userDO = BeanUtil.toBean(requestParam, UserDO.class);
        userDO.setUserPic("https://www.keaitupian.cn/cjpic/frombd/1/253/4212546809/2253368881.jpg");
        int insert = baseMapper.insert(userDO);
        if (insert < 1) {
            throw new ClientException(UserErrorCodeEnum.USER_SAVE_ERROR);
        }
        //数据一致性
        userDetailMapper.insert(UserDetailDO.builder().userId(userDO.getUserId()).build());
        return null;
    }

    @Override
    public String invite() {
        // 安全获取用户 ID
        String loginId = StpUtil.getLoginId().toString();
        if (loginId == null) {
            throw new ClientException(UserErrorCodeEnum.USER_TOKEN_FAIL);
        }
        Long userId = Long.parseLong(loginId);

        // 配置化的重试次数和过期时间
        int maxRetryCount = 10; // 可以从配置文件中读取
        long expireTimeMinutes = 10; // 可以从配置文件中读取

        for (int retryCount = 0; retryCount < maxRetryCount; retryCount++) {
            try {
                // 生成邀请码
                String code = ShareCodeUtils.idToCode(userId);

                // 使用 Redis 的 SADD 原子操作
                Long added = stringRedisTemplate.opsForSet().add("invitation_codes", code);
                if (added != null) {
                    // 设置过期时间
                    stringRedisTemplate.expire("invitation_codes", expireTimeMinutes, TimeUnit.MINUTES);
                    return code;
                }
            } catch (Exception e) {
                // 捕获 Redis 操作异常并记录日志
                log.error("Redis operation failed during invitation code generation: ", e);
                if (retryCount == maxRetryCount - 1) {
                    throw new ClientException(UserErrorCodeEnum.USER_GET_INVITE_CODE_ERROR);
                }
            }
        }
        // 如果达到最大重试次数，抛出异常
        throw new ClientException(UserErrorCodeEnum.USER_GET_INVITE_CODE_ERROR);
    }

    @Override
    public void joinFamilyByInviteCode(String requestParam) {
        //判断redis里面有没有邀请码
        if (Boolean.FALSE.equals(stringRedisTemplate.opsForSet().isMember("invitation_codes", requestParam))) {
           throw new ClientException(UserErrorCodeEnum.USER_INVITE_CODE_ERROR);
        }
        // 安全获取用户 ID
        String userId = StpUtil.getLoginId().toString();
        if (userId == null) {
            throw new ClientException(UserErrorCodeEnum.USER_TOKEN_FAIL);
        }
        //获取家族id
        Integer invitedID = Integer.parseInt(ShareCodeUtils.codeToId(requestParam).toString());
        String familyId = stringRedisTemplate.opsForValue().get(invitedID);
        if (familyId == null || familyId.isEmpty()) {
            familyId = userMapper.getFamilyIdByUserId(invitedID);
        }
        if (familyId == null || familyId.isEmpty()) {
            throw new ClientException(UserErrorCodeEnum.USER_INVITE_CODE_ERROR);
        }
        stringRedisTemplate.opsForValue().set(userId, String.valueOf(familyId));

        //更新用户表
        baseMapper.update(null, Wrappers.lambdaUpdate(UserDO.class)
                .set(UserDO::getFamilyId, familyId)
                .eq(UserDO::getUserId, Integer.parseInt(userId)));
    }


    @Override
    public void updateUserPic(MultipartFile file) throws Exception {
        if (file == null || file.isEmpty()) {
            throw new ClientException("文件不能为空");
        }

        // 获取文件名
        String fileName = file.getOriginalFilename();
        if (fileName == null) {
            throw new ClientException("上传失败，请重新上传");
        }

        // 获取文件后缀
        String fileExtension = getFileExtension(fileName);
        if (fileExtension == null || fileExtension.isEmpty()) {
            throw new ClientException("上传失败，请重新上传");
        }

        // 允许的图片后缀
        String[] allowedExtensions = {"jpg", "jpeg", "png", "gif"};
        boolean isValidExtension = false;
        for (String extension : allowedExtensions) {
            if (fileExtension.equalsIgnoreCase(extension)) {
                isValidExtension = true;
                break;
            }
        }

        if (!isValidExtension) {
            throw new ClientException("上传失败，请重新上传");
        }

        Result<String> stringResult = fileController.uploadIcon(file);
        if (stringResult.isSuccess()) {
            // 更新用户头像
            baseMapper.update(null, Wrappers.lambdaUpdate(UserDO.class)
                    .set(UserDO::getUserPic, stringResult.getData())
                    .eq(UserDO::getUserId, StpUtil.getLoginId()));
        } else {
            throw new ClientException("上传失败，请重新上传");
        }

    }

    private String getFileExtension(String fileName) {
        if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) {
            return fileName.substring(fileName.lastIndexOf(".") + 1);
        } else {
            return null;
        }
    }



}
 